package com.wdciti.sccp.iot.gateway.endpoint.pib;

import com.wdciti.sccp.iot.gateway.domain.PersonTagBind;
import com.wdciti.sccp.iot.gateway.domain.TagPosition;
import com.wdciti.sccp.iot.springvertx.annotation.VerticleBean;
import io.netty.handler.codec.mqtt.MqttQoS;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.shareddata.LocalMap;
import io.vertx.mqtt.MqttClient;
import io.vertx.mqtt.MqttClientOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;

/**
 * @author JINWEN
 * 收到MQTT endpoint发送来的消息，按时序数据库格式转发时序数据库存储。
 */
@Slf4j
@VerticleBean(isWorker = false)
public class savePibPositionDataVerticle extends AbstractVerticle {

    private static final String SEND_DATA_BUS_ADDR = "addr:location/now/pib";


    @Value("${iotdb.host}")
    private String mqttIp;

    @Value("${iotdb.mqtt.port}")
    private Integer mqttPort;

    @Value("${iotdb.username}")
    private String mqttUserName;

    @Value("${iotdb.password}")
    private String mqttPassWord;
    private static final String PREFIX = "p_";

    @Override
    public void start() {

        MqttClientOptions options = new MqttClientOptions().setUsername(mqttUserName).setPassword(mqttPassWord);
        MqttClient client = MqttClient.create(vertx, options).connect(mqttPort, mqttIp,
                res -> System.out.println("iotdb::mqtt connected! " + res.succeeded()));

        vertx.eventBus().<JsonObject>consumer(SEND_DATA_BUS_ADDR).handler(msg -> {
            //log.debug("RECEIVE msg From busAddr:{}, msg:{}", SEND_DATA_BUS_ADDR, msg.body());
            TagPosition position = msg.body().mapTo(TagPosition.class);
            //过滤品珀的定位数据。
            if (position.getLatitude() <= 0 || position.getLongitude() <= 0 ) {
                return;
            }
            PersonTagBind bind = findBindInWhiteList(position);
            if (bind != null) {
                //转换渠道ID->平台ID，渠道ID已经完成了他的使命。渠道之ID常变，而平台之ID常不变。
                position.setTagId(bind.getPersonId());
                //放缓存
                vertx.sharedData().getLocalMap(position.getChannel() + "_now")
                        .put(position.getTagId(), JsonObject.mapFrom(position));
                //格式化，发IotDB
                JsonObject send = revertObj(position);
                log.info("send msg to iotdb:{}", send);
                client.publish(send.getString("device"), send.toBuffer(), MqttQoS.AT_LEAST_ONCE, false, false);
            }
        });

    }


    //查白名单，在白名单里面的才存
    private PersonTagBind findBindInWhiteList(TagPosition position) {
        if(position == null){
            return null;
        }
        if(StringUtils.isEmpty(position.getTagId())){
            //log.info("定位记录数据没有ID");
            return null;
        }
        String cacheName = PersonTagBind.whiteListPrefix() + position.getChannel();
        LocalMap<String, JsonObject> whiteList = vertx.sharedData().getLocalMap(cacheName);
        //log.info("select PersonTagBind in whiteListCache: {}",cacheName);
        if (whiteList == null || whiteList.isEmpty()) {
            log.info("Nothing in whiteListCache: {}",cacheName);
            return null;
        }
        JsonObject jsonObject = whiteList.getOrDefault(position.getTagId(), JsonObject.of());
        if (!jsonObject.isEmpty()) {
            return jsonObject.mapTo(PersonTagBind.class);
        } else {
            log.debug("Not Find DataPoint In WhiteList! TagPosition:{}", position);
            return null;
        }

    }

    private JsonObject revertObj(TagPosition input) {
        String device = "root.position.pib." + PREFIX + input.getTagId();
        return JsonObject.of().put("device", device)
                .put("timestamp", input.getTimestamp())
                .put("measurements", new JsonArray()
                        .add(0, "longitude")
                        .add(1, "latitude")
                        .add(2, "high"))
                .put("values", new JsonArray()
                        .add(0, input.getLongitude())
                        .add(1, input.getLatitude())
                        .add(2, input.getHigh())
                );
    }
}
